using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Magiq.Sql.Support;
using Magiq.Support;

namespace Magiq.Sql.Query
{
    public class MagiqToSqlQueryable<T> : IQueryable<T>, IEntitySetAdapterProvider {
        private readonly IQueryable<T> baseQueryable;

        public MagiqToSqlQueryable(EntitySetAdapter entitySetAdapter) {
            EntitySetAdapter = entitySetAdapter;
            var member = entitySetAdapter.Member;
            var elementType = member.Association.OtherType.Type;

            var parameter = Expression.Parameter(elementType, "x");

            var table = entitySetAdapter.DataContext.GetTable(member.Association.OtherType.Type);
            var provider = (IQueryProvider) table;

            Expression body = null;

            for (var i = 0; i < member.Association.ThisKey.Count; i++) {
                var parentKeyValue = entitySetAdapter.Instance.Property(member.Association.ThisKey[i].Name);
                var childKeyName = member.Association.OtherKey[i].Name;
                var e = Expression.Equal(Expression.Property(parameter, childKeyName),
                                         Expression.Constant(parentKeyValue));
                body = body == null ? e : Expression.AndAlso(body, e);
            }
            var lambda = Expression.Lambda(body, parameter);
            baseQueryable = (IQueryable<T>) provider.CreateQuery(Expression.Call(typeof (Queryable),
                                                                                 "Where",
                                                                                 new[] {table.ElementType},
                                                                                 table.Expression,
                                                                                 Expression.Quote(lambda)));
        }

        #region IEntitySetAdapterProvider Members

        public EntitySetAdapter EntitySetAdapter { get; set; }

        #endregion

        #region IQueryable<T> Members

        public IEnumerator<T> GetEnumerator() {
            return baseQueryable.GetEnumerator();
        }

        public Expression Expression {
            get { return baseQueryable.Expression; }
        }

        public Type ElementType {
            get { return baseQueryable.ElementType; }
        }

        public IQueryProvider Provider {
            get { return baseQueryable.Provider; }
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }

        #endregion
    }
}